﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using SdmxMl.Common;

namespace SdmxMl.Excel
{
    /// <summary>
    /// Helper class to record kind of annotations associated to Artefact
    /// and elements of annotation that are used.
    /// </summary>
    public class AnnotationCount
    {
        #region Properties

        private int count;
        public int Count
        {
            get { return count; }
        }

        private bool internationalized;
        public bool Internationalized
        {
            get { return internationalized; }
        }

        private bool hasTitle;
        public bool HasTitle
        {
            get { return hasTitle; }
        }

        private bool hasUrn;
        public bool HasUrn
        {
            get { return hasUrn; }
        }

        
        private Annotation annot;
        public Annotation Annot
        {
            get { return annot; }
        }
        #endregion

        #region C'tor

        public AnnotationCount(Annotation a)
        {
            annot = a;
            count = 1;
            internationalized = a.Text.IsInternationalized;
            hasTitle = string.IsNullOrEmpty(a.Title) == false;
            hasUrn = a.Url != null;
        }
        #endregion

        #region Update Methods

        /// <summary>
        /// Update count of annotation and update sub info if required.
        /// </summary>
        /// <param name="internat">true if internationalized</param>
        /// <param name="title">true if title used in annotation</param>
        /// <param name="urn">true if urn used in annotation</param>
        public void Add(bool internat, bool title, bool urn)
        {
            count++;
            UpdateSubInfo(internat, title, urn);
        }

        /// <summary>
        /// Update from a previous set
        /// </summary>
        /// <param name="nb">nb in prev set</param>
        /// <param name="internat">true if internationalized</param>
        /// <param name="title">true if title used in annotation</param>
        /// <param name="urn">true if urn used in annotation</param>
        public void UpdateMax(int nb, bool internat, bool title, bool urn)
        {
            if (nb > count)
                count = nb;
            UpdateSubInfo(internat, title, urn);
        }

        private void UpdateSubInfo(bool internat, bool title, bool urn)
        {
            if (internat)
                internationalized = true;
            if (title)
                hasTitle = true;
            if (urn)
                hasUrn = true;
        }
        #endregion
    }


    /// <summary>
    /// Determines Annotations types and instances in an item
    /// </summary>
    public class AnnotationInventory
    {
        #region Properties

        private DataTable tbInfoSel;
        public DataTable TableInfoSelection { get { return tbInfoSel; } }

        private Dictionary<string, AnnotationCount> dico;
        public Dictionary<string, AnnotationCount> Dico
        {
            get { return dico; }
        }

        public int FullCount
        {
            get
            {
                int count = 0;
                foreach (KeyValuePair<string, AnnotationCount> kvp in dico)
                    count += kvp.Value.Count;

                return count;
            }
        }

        #endregion

        #region Internal Members

        private Dictionary<string, AnnotationCount> dicoRow;

        #endregion

        #region C'tor

        public AnnotationInventory()
        {
            dico = new Dictionary<string, AnnotationCount>(16);
        }
        #endregion

        #region Inventory method

        /// <summary>Inventory annotations of an annotation list. </summary>
        /// <param name="ann">the annotation list</param>
        /// <param name="excludeNote">If true annotations of type "NOTE" are skipped</param>
        public void Inventory(AnnotationList ann, bool excludeNote)
        {
            if (ann != null && ann.Count > 0)
            {
                dicoRow = new Dictionary<string, AnnotationCount>();
                foreach (Annotation a in ann)
                {
                    // As in 2.0 codelist we simulate description as a NOTE in SDMX, skip this case if requested
                    if (excludeNote && a.Type == "NOTE")
                        continue;

                    // Annotations differencied by type
                    string key = a.Type;
                    if (dicoRow.ContainsKey(key))
                    {
                        // Update sub info according to same annot type instance found
                        AnnotationCount ac = dicoRow[key];
                        ac.Add(a.Text.IsInternationalized, string.IsNullOrEmpty(a.Title) == false, a.Url != null);
                    }
                    else
                    {
                        // New type of annotation
                        AnnotationCount ac = new AnnotationCount(a);
                        dicoRow.Add(key, ac);
                    }
                }

                // Now report to global dico linked to whole artefact
                foreach (KeyValuePair<string, AnnotationCount> kvp in dicoRow)
                {
                    if (dico.ContainsKey(kvp.Key))
                        dico[kvp.Key].UpdateMax(kvp.Value.Count, kvp.Value.Internationalized, kvp.Value.HasTitle, kvp.Value.HasUrn);
                    else
                        dico.Add(kvp.Key, kvp.Value);
                }

            }
        }
        #endregion

        #region Header generation Helper

        public void GenerateAnnotationHeader(List<string> headerColitems)
        {
            // For each annotation, 6 columns ANN_TYPE, ANN_TITLE, ALNN_TEXT_lg.., ANN_URN
            foreach (KeyValuePair<string, AnnotationCount> kvp in Dico)
            {
                for (int i = 0; i < kvp.Value.Count; i++)
                {
                    string detail = string.Empty;
                    string instanceCount = string.Empty;
                    if (kvp.Value.Count > 1)
                        instanceCount = string.Format("_{0}", i + 1);
                    if (kvp.Value.HasTitle)
                    {
                        headerColitems.Add(kvp.Value.Annot.Type + instanceCount + "_Title");
                        detail = "_Text";
                    }

                    if (kvp.Value.Internationalized)
                    {
                        foreach (string lg in SdmxMl.Common.LangSupport.SupportedLanguages)
                            headerColitems.Add(kvp.Value.Annot.Type + instanceCount + detail + "_" + lg);
                    }
                    else
                    {
                        headerColitems.Add(kvp.Value.Annot.Type + instanceCount + detail);
                    }
                    if (kvp.Value.HasUrn)
                    {
                        headerColitems.Add(kvp.Value.Annot.Type + instanceCount + "_Url");
                    }
                }
            }
        }

        public DataTable GenDataTableInfo()
        {
            DataTable t = new DataTable();
            t.Columns.Add(new DataColumn("Sel", typeof(bool)));
            t.Columns.Add(new DataColumn("Ann", typeof(string)));
            t.Columns.Add(new DataColumn("Count", typeof(int)));
            t.Columns.Add(new DataColumn("TitleUsed", typeof(bool)));
            t.Columns.Add(new DataColumn("Internat", typeof(bool)));
            t.Columns.Add(new DataColumn("UrnUsed", typeof(bool)));

            // Now fill
            foreach (KeyValuePair<string, AnnotationCount> kvp in Dico)
            {
                    t.Rows.Add(new object[] 
                    { 
                        false, 
                        kvp.Value.Annot.Type,
                        kvp.Value.Count,
                        kvp.Value.HasTitle,
                        kvp.Value.Internationalized,
                        kvp.Value.HasUrn
                    });
            }

            tbInfoSel = t;
            return tbInfoSel;

        }

        public bool IsSelectedAnnot(string id)
        {
            if (tbInfoSel == null)
                return true;
            else
            {
                foreach (DataRow row in tbInfoSel.Rows)
                    if (row["Ann"].ToString() == id)
                        return Convert.ToBoolean(row["Sel"]);
            }
            return false;
            
        }
        #endregion


    }
}
